#include "tbcore/reflection/variant.hpp"

#include "tbcore/base/base.hpp"
#include "tbcore/base/arbitrary_cast.hpp"

#include "tbcore/reflection/reflection.hpp"
#include "tbcore/reflection/transform.hpp"
#include "tbcore/reflection/collection_trait.hpp"
#include "tbcore/reflection/allocator.hpp"

TB_NAMESPACE_BEGIN

Variant::Variant() 
  : data_() {
  memset(&data_.value, 0, sizeof(data_.value));
	data_.value.ptr = nullptr;
  data_.typeId = kNullType;
  data_.typeFlag = kNullType;
  data_.dataFlag = kNullDataFlag; 
  data_.isShared = 0;
}

Variant::Variant( const Variant& rhs ) 
  : data_(rhs.data_) {
  if (data_.isShared) {
    TB_ASSERT(data_.refCount);
    data_.refCount->fetch_add(1);
  }
}

Variant::Variant(Variant&& rhs)
  : data_(rhs.data_) {
  rhs.data_.typeId = 0;
  rhs.data_.typeFlag = kValueTypeFlag;
  rhs.data_.dataFlag = kNullType;
}

Variant& Variant::operator=(Variant&& rhs) {
  data_ = rhs.data_;
  return *this;
}

Variant::Variant( uint32 typeId, uint8 typeFlag, uint8 dataFlag )
  : data_() {
  data_.typeFlag = typeFlag;
  data_.dataFlag = dataFlag;
  data_.typeId = typeId;
  data_.isShared = 0;

	if (kStringType == typeId) {
		data_.value.ptr = TB_OPTIMIZED_NEW(String_T);
		AsStringT()->size = 0;
		AsStringT()->str = nullptr;
    data_.isShared = 1;
	} else if (kObjectIdType == typeId) {
		data_.value.ptr = TB_OPTIMIZED_NEW(ObjectId_T);
		AsObjectIdT()->oid = nullptr;
    data_.isShared = 1;
	} else if (kObjectDataFlag == dataFlag || kReferenceTypeFlag == typeFlag || kRefSharedPtrTypeFlag == typeFlag) {
		data_.value.ptr = TB_OPTIMIZED_NEW(Object_T);
		AsObjectT()->obj = nullptr;
		AsObjectT()->alloc = nullptr;
    data_.isShared = 1;
	} else if (kMapDataFlag == dataFlag) {
		data_.value.ptr = TB_OPTIMIZED_NEW(Map_T);
		AsMapT()->size = 0;
		AsMapT()->capacity = 0;
		AsMapT()->elements = nullptr;
    data_.isShared = 1;
	} else if (kPairDataFlag == dataFlag) {
		data_.value.ptr = TB_OPTIMIZED_NEW(Pair_T);
		AsPairT()->key = nullptr;
		AsPairT()->value = nullptr;
    data_.isShared = 1;
	} else if (kArrayDataFlag == dataFlag) {
		data_.value.ptr = TB_OPTIMIZED_NEW(Array_T);
		AsArrayT()->size = 0;
		AsArrayT()->capacity = 0;
		AsArrayT()->elements = 0;
    data_.isShared = 1;
  } else if (kSharedPtrTypeFlag == typeFlag) {
    data_.isShared = 1;
  }

  if (data_.isShared) {
    data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
  }
}

Variant::Variant( bool b )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kBoolType;
  data_.isShared = 0;
  data_.value.num.i64 = b ? 0x00000001 : 0x00000000;
}

Variant::Variant( int8 i8 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kInt8Type;
  data_.isShared = 0;
  data_.value.num.i8.i8 = i8;
}

Variant::Variant( uint8 u8 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kUint8Type;
  data_.isShared = 0;
  data_.value.num.u8.u8 = u8;
}

Variant::Variant( int16 i16 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kInt16Type;
  data_.isShared = 0;
  data_.value.num.i16.i16 = i16;
}

Variant::Variant( uint16 u16 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kUint16Type;
  data_.isShared = 0;
  data_.value.num.u16.u16 = u16;
}

Variant::Variant( int32 i32 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kInt32Type;
  data_.isShared = 0;
  data_.value.num.i32.i32 = i32;
}

Variant::Variant( uint32 u32 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kUint32Type;
  data_.isShared = 0;
  data_.value.num.u32.u32 = u32;
}

Variant::Variant( int64 i64 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kInt64Type;
  data_.isShared = 0;
  data_.value.num.i64 = i64;
}

Variant::Variant( uint64 u64 )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kUint64Type;
  data_.isShared = 0;
  data_.value.num.u64 = u64;
}

Variant::Variant( float f )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kFloatType;
  data_.isShared = 0;
  data_.value.num.f.f = f;
}

Variant::Variant( double d )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kDoubleType;
  data_.isShared = 0;
  data_.value.num.d = d;
}

Variant::Variant( const std::string& str )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kStringType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
	data_.value.ptr = TB_OPTIMIZED_NEW(String_T);
  AsStringT()->size = (uint32)str.size();
	AsStringT()->str = (char*)TB_OPTIMIZED_MALLOC(AsStringT()->size);
	memcpy(AsStringT()->str, str.c_str(), AsStringT()->size);
}

Variant::Variant( const string16& str )
  : data_() {
  memset(&data_.value, 0, sizeof(data_.value));
  std::string str_(UTF16ToUTF8(str));
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kStringType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
	data_.value.ptr = TB_OPTIMIZED_NEW(String_T);
	AsStringT()->size = (uint32)str_.size();
	AsStringT()->str = (char*)TB_OPTIMIZED_MALLOC(AsStringT()->size);
	memcpy(AsStringT()->str, str_.c_str(), AsStringT()->size);
}

Variant::Variant( const char* str, uint32 len )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kStringType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
	data_.value.ptr = TB_OPTIMIZED_NEW(String_T);
	AsStringT()->size = len;
	AsStringT()->str = (char*)TB_OPTIMIZED_MALLOC(AsStringT()->size);
	memcpy(AsStringT()->str, str, AsStringT()->size);
}

Variant::Variant(const char* str)
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kStringType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
  data_.value.ptr = TB_OPTIMIZED_NEW(String_T);
  AsStringT()->size = (uint32)strlen(str);
  AsStringT()->str = (char*)TB_OPTIMIZED_MALLOC(AsStringT()->size);
  memcpy(AsStringT()->str, str, AsStringT()->size);
}

Variant::Variant( const Duration& d )
  : data_() {
  memset(&data_.value, 0, sizeof(data_.value));
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kDurationType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
  data_.value.num.i64 = d.TotalMilliseconds();
}

Variant::Variant( const DateTime& d )
  : data_() {
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullDataFlag;
  data_.typeId = kDatetimeType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW(boost::atomic_int), ScalableDeleter<boost::atomic_int>());
  data_.refCount->fetch_add(1);
  data_.value.num.i64 = d.TotalMilliseconds();
}

Variant::Variant(const UniqueId& oid)
	: data_() {
	data_.typeFlag = kValueTypeFlag;
	data_.dataFlag = kNullDataFlag;
	data_.typeId = kObjectIdType;
  data_.isShared = 1;
  data_.refCount.reset(TB_OPTIMIZED_NEW_ARG(boost::atomic_int, 1), ScalableDeleter<boost::atomic_int>());
	data_.value.ptr = TB_OPTIMIZED_NEW(ObjectId_T);
	AsObjectIdT()->oid = TB_OPTIMIZED_NEW_ARG(UniqueId, oid);
}

Variant& Variant::operator=( const Variant& rhs ) {
  data_ = rhs.data_;
  if (data_.isShared) {
    TB_ASSERT(data_.refCount);
    data_.refCount->fetch_add(1);
  }
  return *this;
}

Variant::~Variant() {
  Destroy();
}

void Variant::Assign( Variant& rhs ) {
  this->operator=(rhs);
}

Variant::Object_T Variant::InternalCopyObject(const Object_T* src, uint32 typeId) const {
  Object_T result;
  result.obj = src->alloc->Malloc();
  if (IsUserTypeId(typeId)) {
    reflection::DeepCopy(src->obj, result.obj, typeId);
  } else {
    memcpy(result.obj, src->obj, src->alloc->TypeSize());
  }
  result.alloc = src->alloc;
  return result;
}

Variant::Pair_T Variant::InternalCopyPair(const Pair_T* src) const {
  Pair_T result = {new Variant(), new Variant()};
  *result.key = src->key->Copy();
  *result.value = src->value->Copy();
  return result;
}

Variant::Map_T Variant::InternalCopyMap(const Map_T* src) const {
  Map_T result;
	result.size = src->size;
	result.capacity = src->size;
	result.elements = (Pair_T*)TB_OPTIMIZED_MALLOC(sizeof(Pair_T) * result.size);
	for (uint32 i = 0; i < result.size; ++i) {
    *(result.elements + i) = InternalCopyPair(src->elements + i);
  }
  return result;
}

Variant::Array_T Variant::InternalCopyArray(const Array_T* src) const {
  Array_T result;
	result.size = src->size;
	result.capacity = result.size;
  result.elements = (Variant**)TB_OPTIMIZED_MALLOC(sizeof(Variant*) * result.size);
	for (uint32 i = 0; i < result.size; ++i) {
    *(result.elements + i) = new Variant((*(src->elements + i))->Copy());
  }
  return result;
}

Variant::String_T Variant::InternalCopyString(const String_T* src) const {
	String_T result;
	result.size = src->size;
	result.str = (char*)TB_OPTIMIZED_MALLOC(result.size);
	memcpy(result.str, src->str, src->size);
	return result;
}

Variant::ObjectId_T Variant::InternalCopyObjectId(const ObjectId_T* src) const {
	ObjectId_T result;
  result.oid = TB_OPTIMIZED_NEW_ARG(UniqueId, *src->oid);
	return result;
}

Variant Variant::Copy() const {
  TB_ASSERT(kReferenceTypeFlag == data_.typeFlag);

  Variant v(data_.typeId, data_.typeFlag, data_.typeFlag);

  if (kSharedPtrTypeFlag == data_.typeFlag ||
    IsBuildinTypeId(data_.typeId)) {
    v.data_.value = data_.value;
    return v;
  }

	if (kObjectIdType == data_.typeId) {
		*reinterpret_cast<ObjectId_T*>(data_.value.ptr) = InternalCopyObjectId(AsObjectIdT());
	} else if (kStringType == data_.typeId) {
		*reinterpret_cast<String_T*>(data_.value.ptr) = InternalCopyString(AsStringT());
	}

  switch (data_.dataFlag) {
		case kObjectDataFlag: {
			*reinterpret_cast<Object_T*>(data_.value.ptr) = InternalCopyObject(AsObjectT(), data_.typeId);
			break;
		}
		case kPairDataFlag: {
			*reinterpret_cast<Pair_T*>(data_.value.ptr) = InternalCopyPair(AsPairT());
			break;
		}
		case kMapDataFlag: {
			*reinterpret_cast<Map_T*>(data_.value.ptr) = InternalCopyMap(AsMapT());
			break;
		}
		case kArrayDataFlag: {
			*reinterpret_cast<Array_T*>(data_.value.ptr) = InternalCopyArray(AsArrayT());
			break;
		}
  }

  return v;
}

void Variant::Destroy() {
  if (!data_.isShared) {
		return;
	}

  TB_ASSERT(data_.refCount);

  if (data_.refCount->fetch_sub(1) == 1) {
		if (kObjectIdType == data_.typeId) {
			TB_OPTIMIZED_DELETE(AsObjectIdT()->oid);
			TB_OPTIMIZED_DELETE(AsObjectIdT());
		} else if (kStringType == data_.typeId) {
			TB_OPTIMIZED_FREE(AsStringT()->str);
			TB_OPTIMIZED_DELETE(AsStringT());
		} else {
			switch (data_.typeFlag) {
				case kReferenceTypeFlag:
				case kRefSharedPtrTypeFlag: {
					TB_OPTIMIZED_DELETE(AsObjectT());
					goto RESET_DATA;
				}
        case kSharedPtrTypeFlag: {
          VoidPtr* vptr = static_cast<VoidPtr*>(data_.value.ptr);
          TB_OPTIMIZED_DELETE(vptr);
          goto RESET_DATA;
        }
			}
		
			switch (data_.dataFlag) {
				case kObjectDataFlag: {
					AsObjectT()->alloc->Free(AsObjectT()->obj);
					TB_OPTIMIZED_DELETE(AsObjectT());
					break;
				}
				case kPairDataFlag: {
					TB_OPTIMIZED_DELETE(AsPairT()->key);
          TB_OPTIMIZED_DELETE(AsPairT()->value);
					TB_OPTIMIZED_DELETE(AsPairT());
					break;
				}
				case kMapDataFlag: {
					for (uint32 i = 0; i < AsMapT()->size; ++i) {
						Pair_T& pa = *(AsMapT()->elements + i);
            TB_OPTIMIZED_DELETE(pa.key);
            TB_OPTIMIZED_DELETE(pa.value);
					}
					TB_OPTIMIZED_FREE(AsMapT()->elements);
					TB_OPTIMIZED_DELETE(AsMapT());
					break;
				}
				case kArrayDataFlag: {
					for (uint32 i = 0; i < AsArrayT()->size; ++i) {
						Variant* item = *(AsArrayT()->elements + i);
						TB_OPTIMIZED_DELETE(item);
					}
					TB_OPTIMIZED_FREE(AsArrayT()->elements);
					TB_OPTIMIZED_DELETE(AsArrayT());
					break;
				}
			}
		}
  }
RESET_DATA:
	data_.value.ptr = nullptr;
  data_.typeId = 0;
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullType;
  data_.isShared = 0;
  data_.refCount.reset();
}

void *TB::Variant::Detach() {
  if (data_.refCount) {
    TB_SMART_ASSERT(data_.refCount->load() <= 1);
  }
  
  void *d = Data();
  data_.value.ptr = nullptr;
  data_.typeId = 0;
  data_.typeFlag = kValueTypeFlag;
  data_.dataFlag = kNullType;
  data_.isShared = 0;
  data_.refCount.reset();
  return d;
}

void* Variant::Data() const {
  switch (data_.typeFlag) {
		case kComplexTypeFlag: {
			switch (data_.dataFlag) {
				case kPairDataFlag: {
					return const_cast<void*>(static_cast<const void*>(AsPairT()));
				}
				case kMapDataFlag: {
					return const_cast<void*>(static_cast<const void*>(AsMapT()->elements));
				}
				case kArrayDataFlag: {
					return const_cast<void*>(static_cast<const void*>(AsArrayT()->elements));
				}
			}
			break;
		}
		case kPointerTypeFlag:
		case kReferenceTypeFlag:
			return AsObjectT()->obj;
		case kSharedPtrTypeFlag:
      return (static_cast<VoidPtr *>(data_.value.ptr));
		default: {
			if (kObjectDataFlag == data_.dataFlag) {
				return AsObjectT()->obj;
			} else if (kStringType == data_.typeId) {
				return AsStringT()->str;
			} else if (kObjectIdType == data_.typeId) {
				return AsObjectIdT()->oid;
			} else {
				return const_cast<void*>(static_cast<const void*>(&data_.value));
			}
		}
  }

  return nullptr;
}

Variant Variant::FromObject( VoidPtr d, uint32 typeId, reflection::Allocator* alloc ) {
  Variant v(typeId, kSharedPtrTypeFlag, kNullDataFlag);
  VoidPtr* vptr = (VoidPtr*)TB_OPTIMIZED_NEW_ARG(VoidPtr, d);
  v.data_.value.ptr = vptr;
  return v;
}

Variant Variant::FromObject(void* d, uint32 typeId, reflection::Allocator* alloc) {
  Variant v(typeId, kValueTypeFlag, kObjectDataFlag);
  v.AsObjectT()->obj = d;
	v.AsObjectT()->alloc = alloc;
  return v;
}

uint32 Variant::Size() const {
  TB_ASSERT(data_.dataFlag == kArrayDataFlag || data_.dataFlag == kMapDataFlag);

  switch (data_.typeFlag) {
		case kComplexTypeFlag: {
			switch (data_.dataFlag) {
				case kMapDataFlag: {
					return AsMapT()->size;
				}
				case kArrayDataFlag: {
					return AsArrayT()->size;
				}
			}
		}
  }

  return 0;
}

void Variant::PushBack( const Variant& val ) {
  TB_ASSERT(data_.dataFlag == kArrayDataFlag);
	if (AsArrayT()->capacity <= 0) {
    AsArrayT()->capacity = 16;
		AsArrayT()->elements =
			(Variant**)TB_OPTIMIZED_MALLOC(sizeof(Variant*) * AsArrayT()->capacity);
  }

	if (AsArrayT()->size >= AsArrayT()->capacity) {
		AsArrayT()->capacity *= 2;
		AsArrayT()->elements =
      (Variant**)TB_OPTIMIZED_REALLOC(AsArrayT()->elements, sizeof(Variant*) * AsArrayT()->capacity);
  }

	*(AsArrayT()->elements + AsArrayT()->size) = TB_OPTIMIZED_NEW_ARG(Variant, val);
	AsArrayT()->size++;
}

//todo: add memory pool
void Variant::Insert( const Variant& key, const Variant& val ) {
  TB_ASSERT(data_.dataFlag == kMapDataFlag);
	if (AsMapT()->capacity <= 0) {
		AsMapT()->capacity = 16;
		AsMapT()->elements =
			(Pair_T*)TB_OPTIMIZED_MALLOC(sizeof(Pair_T) * AsMapT()->capacity);
  }

	if (AsMapT()->size >= AsMapT()->capacity) {
		AsMapT()->capacity *= 2;
		AsMapT()->elements =
			(Pair_T*)TB_OPTIMIZED_REALLOC(AsMapT()->elements, sizeof(Pair_T) * AsMapT()->capacity);
  }

	Pair_T* pr = AsMapT()->elements + AsMapT()->size;
	pr->key = TB_OPTIMIZED_NEW_ARG(Variant, key);
	pr->value = TB_OPTIMIZED_NEW_ARG(Variant, val);
	AsMapT()->size++;
}

bool Variant::IsBool() const {
  return kBoolType == data_.typeId;
}

bool Variant::IsInt8() const {
  return kInt8Type == data_.typeId;
}

bool Variant::IsUInt8() const {
  return kUint8Type == data_.typeId;
}

bool Variant::IsInt16() const {
  return kInt16Type == data_.typeId;
}

bool Variant::IsUInt16() const {
  return kUint16Type == data_.typeId;
}

bool Variant::IsInt32() const {
  return kInt32Type == data_.typeId;
}

bool Variant::IsUInt32() const {
  return kUint32Type == data_.typeId;
}

bool Variant::IsInt64() const {
  return kInt64Type == data_.typeId;
}

bool Variant::IsUInt64() const {
  return kUint64Type == data_.typeId;
}

bool Variant::IsFloat() const {
  return kFloatType == data_.typeId;
}

bool Variant::IsDouble() const {
  return kDoubleType == data_.typeId;
}

bool Variant::IsObjectId() const {
	return kObjectIdType == data_.typeId;
}

bool Variant::GetBool() const {
  return data_.value.num.i64 != 0;
}

int8 Variant::GetInt8() const {
  return data_.value.num.i8.i8;
}

uint8 Variant::GetUInt8() const {
  return data_.value.num.u8.u8;
}

int16 Variant::GetInt16() const {
  return data_.value.num.i16.i16;
}

uint16 Variant::GetUInt16() const {
  return data_.value.num.u16.u16;
}

int32 Variant::GetInt32() const {
  return data_.value.num.i32.i32;
}

uint32 Variant::GetUInt32() const {
  return data_.value.num.u32.u32;
}

int64 Variant::GetInt64() const {
  return data_.value.num.i64;
}

uint64 Variant::GetUInt64() const {
  return data_.value.num.u64;
}

float Variant::GetFloat() const {
  return data_.value.num.f.f;
}

double Variant::GetDouble() const {
  return data_.value.num.d;
}

UniqueId Variant::GetObjectId() const {
	TB_ASSERT(kObjectIdType == data_.typeId);
	return *reinterpret_cast<UniqueId*>(AsObjectIdT()->oid);
}

Variant* Variant::GetKey() const {
  TB_ASSERT(kPairDataFlag == data_.dataFlag);
  return AsPairT()->key;
}

Variant* Variant::GetValue() const {
  TB_ASSERT(kPairDataFlag == data_.dataFlag);
	return AsPairT()->value;
}

bool Variant::IsUserType() const {
	return data_.typeId > kUserType;
}

bool Variant::IsBuildinType() const {
	return data_.typeId > kNullType && data_.typeId < kUserType;
}

bool Variant::IsSimpleType() const {
	return data_.typeId > kNullType && data_.typeId <= kDoubleType;
}

void Variant::SetPair(const Variant& key, const Variant& val) {
	TB_ASSERT(IsPair());
	if (AsPairT()->key) {
		new (AsPairT()->key) Variant(key);
	} else {
		AsPairT()->key = new Variant(key);
	}
	
	if (AsPairT()->value) {
		new (AsPairT()->value) Variant(val);
	} else {
		AsPairT()->value = new Variant(val);
	}
}

Variant** Variant::GetArray() const {
	TB_ASSERT(IsArray());
	return AsArrayT()->elements;
}

Variant::Pair_T* Variant::GetMap() const {
	TB_ASSERT(IsMap());
	return AsMapT()->elements;
}

void TB::Variant::Clear() {
  if (IsArray()) {
    AsArrayT()->size = 0;
  } else if (IsMap()) {
    AsMapT()->size = 0;
  }
}

int Variant::Compare(const Variant& rhs) const {
	if (IsSharedPtr() && rhs.IsSharedPtr()) {
    return (static_cast<VoidPtr *>(data_.value.ptr))->get() 
      == (static_cast<VoidPtr *>(rhs.data_.value.ptr))->get() ? 0 : -1;
	}

	if (IsSimpleType() && rhs.IsSimpleType()) {
		double r = this->Value<double>() - rhs.Value<double>();
		return r > 0 ? 1 : (r < 0 ? -1 : 0);
	}

	if (data_.typeId == rhs.TypeId()) {
		switch (data_.typeId) {
			case kBoolType:
			case kInt8Type:
			case kUint8Type:
			case kInt16Type:
			case kUint16Type:
			case kInt32Type:
			case kUint32Type:
			case kInt64Type:
			case kUint64Type:
			case kFloatType:
			case kDoubleType:
			case kEnumType: {
				double r = this->Value<double>() - rhs.Value<double>();
				return r > 0 ? 1 : (r < 0 ? -1 : 0);
			}
			case kDurationType: 
			case kDatetimeType: {
				int64 r = this->Value<int64>() - rhs.Value<int64>();
				return r > 0 ? 1 : (r < 0 ? -1 : 0);
			}
			case kStringType: {
				_STD string ls = this->Value<_STD string>();
				_STD string rs = rhs.Value<_STD string>();
				if (ls.size() != rs.size()) {
					_STD size_t r =  ls.size() - rs.size();
					return r > 0 ? 1 : (r < 0 ? -1 : 0);
				}
				return strcmp(ls.c_str(), rs.c_str());
			}
			case kObjectIdType: {
				UniqueId lo = this->Value<UniqueId>();
				UniqueId ro = rhs.Value<UniqueId>();
				return memcmp(lo.ConstData(), ro.ConstData(), UniqueId::kUniqueIdSize);
			}						
		}
	}
	return -1;
}

_STD string Variant::ToString() const {
  if (IsObject()) {
    return PrettyStringifyTransform().Stringify(this);
  } else {
    return BuildinTypeToString(this);
  }
}

TB_NAMESPACE_END